<template>
    <div class="goods-sku">
    <!-- 外层循环生成dl行，有哪些规格：颜色，尺寸  -->
      <dl v-for="spec in goods.specs" :key="spec.name">
        <dt>{{spec.name}}</dt>
        <dd>
            <!-- 内层循环列：即每种规格可供选择的具体项，如白色、蓝色、20mm -->
            <template v-for="item in spec.values" :key="item.name">
                <!-- 有图片优先展示图片 -->
                <!-- item.selected 为自定义属性，后台数据并没有
                    作用：通过这个属性控制当前规格按钮是否选中
                 -->
                <img @click="changeSku(item,spec)"
                v-if="item.picture"
                :class="{selected:item.selected,disabled:item.disabled}"
                :src="item.picture">
                <!-- 否则展示文字 -->
                <span v-else @click="changeSku(item,spec)" :class="{selected:item.selected,disabled:item.disabled}">{{item.name}}</span>
            </template>
        </dd>
      </dl>
    </div>
  </template>
<script>

// 需求1：根据后台返回的规格列表得到一个路径字典
// 目的1：不同规格的按钮选择之后，需要去路径字典中查询，是否有匹配的规格
// 如果存在，按钮不禁用，否则禁用

// 需求2：禁用按钮
// 1.获取选中的值 -> 按顺序将规格存到数组中
// 比如选中了蓝色、20、中国，得到数组['蓝色','20','中国']
// 比如选中了蓝色、20、中国，得到数组['蓝色','10','undefined']
// 2.把得到的数组过滤掉（fillter）假值，把筛选后的数组通过join()，
// 拼接成一个字符串，作为key 去字典中查询匹配
// 3.如果查询匹配到了，不禁用，否则不禁用，通过控制对象的disabled的属性

import getPowerSet from '@/vendor/power-set'
const spliter = '★'
// 定义函数：将规格转换成字典 得到路径对象
const getPathMap = (skus) => {
  // 定义一个路径字典
  const pathMap = {}
  skus.forEach(sku => {
    // 筛选出有效的sku,即库存大于0的sku
    if (sku.inventory > 0) {
      // 得到有效的sku的规格的数组
      // console.log(sku)
      const valueArr = sku.specs.map(item => item.valueName)
      // console.log(valueArr)
      // 得到所有可组合的sku的子级集合
      const valueArrPowerSet = getPowerSet(valueArr)
      // console.log(valueArrPowerSet)
      // 通过子级集合生成路径字典
      // 遍历子级数组
      valueArrPowerSet.forEach(arr => {
        const key = arr.join(spliter)
        if (pathMap[key]) {
          // 有这个key,就做数组的追加
          pathMap[key].push(sku.id)
        } else {
          // 没有这个key
          pathMap[key] = [sku.id]
        }
      })
    }
  })
  // 返回对象
  return pathMap
}

// 控制按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 每次重新选择后，更新按钮的禁用状态
  // console.log(getSelectedSpec(specs))
  const selectedJSON = JSON.stringify(getSelectedSpec(specs))
  specs.forEach((spec, i) => {
    spec.values.forEach(btnObj => {
      const selectedValues = JSON.parse(selectedJSON)
      selectedValues[i] = btnObj.name
      const key = selectedValues.filter(v => v).join(spliter)
      // 判断组合后的情况，在字典中是否能找到
      if (pathMap[key]) {
        btnObj.disabled = false
      } else {
        btnObj.disabled = true
      }
    })
  })
}

// 获取选中的规格的值
// 原则：得到的结果要保证顺序 [undefined, undefined, undefined]
function getSelectedSpec (specs) {
  const arr = []
  specs.forEach((spec, i) => {
    // 根据spec中values中找是否有，selected为true的，把selected为true的那个按钮存储起来
    const btnObj = spec.values.find(item => item.selected)
    if (btnObj) {
      arr[i] = btnObj.name
    } else {
      arr[i] = undefined
    }
  })
  return arr
}

// // 初始化默认选中具体规则（回显）
// const initDefaultSelected = (goods, skuId) => {
//   // 根据skuId去 goods.skus中查找sku对象
//   const sku = goods.skus.find(sku => sku.id === skuId)
//   // 获取sku.specs 中每个规格的值，去goods.spwcs中做比对
//   // 如果sku.specs的值与goods.spwcs的值全等，则就让当前按钮的selected变为true
//   // 遍历goods.specs 数组
//   goods.specs.forEach((item, index) => {
//     // 根据name 查找
//     const btnObj = item.values.find(val => val.name === sku.specs[index].valueName)
//     if (btnObj) {
//       // 找到了，让当前按钮对象选中，selected变为true
//       btnObj.selected = true
//     } else {
//       // 没找到，不选中
//       btnObj.selected = false
//     }
//   })
// }

// 默认选中
// function initDefaultSelected (goods, skuId) {
//   // 1. 找到sku信息
//   // 2. 遍历每个按钮，按钮值和sku的值相同，就选中
//   const sku = goods.skus.find(sku => sku.id === skuId)
//   if (!sku) return
//   goods.specs.forEach((spec, i) => {
//     spec.values.forEach(btnObj => {
//       btnObj.selected = btnObj.name === sku.specs[i].valueName
//     })
//   })
// }

export default {
  name: 'GoodsSku',
  props: {
    // 商品对象参数
    goods: {
      type: Object,
      // 默认值
      default: () => {
        // skus：选择到的具体的商品的规格数组
        // specs:可供选择的规格
        return { skus: [], specs: [] }
      }
    },
    // 具体skuId ,表示默认选中的商品的默认规格
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, { emit }) {
    // 调用getPathMap函数 生成字典
    const pathMap = getPathMap(props.goods.skus)
    // console.log(pathMap)

    // 点击按钮更新按钮禁用状态

    // 判断规格按钮是否选中
    const changeSku = (btnObj, spec) => {
      // 如果当前按钮被禁用，则提前结束
      if (btnObj.disabled) return
      // 如果这个属性为true，说明原来是选中的，点完之后取反
      if (btnObj.selected) {
        btnObj.selected = false
      } else {
        // 排他思想->除了自己，让同类统统不选中
      // 遍历每种规格中的样式
      // eslint-disable-next-line no-return-assign
        spec.values.forEach(btnObj => btnObj.selected = false)
        // 因为后台数据本来就没有selected这个属性，所以如果原先没有选中
        // 会返回undefined，追加selected为true 的属性
        btnObj.selected = true
      }

      // 点击按钮之后，更新按钮的禁用状态
      updateDisabledStatus(props.goods.specs, pathMap)

      // 判断所有的规则都选中了
      // 拿到所有选中值的数组，还需要过滤掉undefined
      const values = getSelectedSpec(props.goods.specs)
      // console.log(values)
      // 过滤掉undefined
      const selectedValues = values.filter(v => v)
      // console.log(selectedValues)
      // 过滤之后，将数组长度和props.goods.specs做对比
      if (selectedValues.length === props.goods.specs.length) {
        // 如果所有规格全选中了
        // 收集选中的数据（sku对象）
        // 根据选中的数组，['黑色'，'30','日本'] 通过join()拼接一个字符串
        const key = selectedValues.join(spliter)
        // 去字典中查找skuId
        // const skuId = pathMap[key][0]
        const [skuId] = pathMap[key]
        // 根据skuId 去goods.skus 数组中查找 真正sku 对象
        const skuObj = props.goods.skus.find(sku => sku.id === skuId)
        // 对规格数组specs做格式化处理，得到字符串文本
        const specsText = skuObj.specs.map(item => {
          const str = `${item.name}:${item.valueName}`
          // map返回的是数组，数组里面装的是什么，取决于return了什么
          return str
        })
        // 发起自定义事件，通知父组件并传入sku对象参数
        emit('finish', {
          ...skuObj,
          specsText: specsText.join(' ')
        }
        )
      }
    }
    return {
      changeSku

    }
  }
}
</script>
  <style scoped lang="less">
  .sku-state-mixin () {
    border: 1px solid #e4e4e4;
    margin-right: 10px;
    cursor: pointer;
    &.selected {
      border-color: @xtxColor;
    }
    &.disabled {
      opacity: 0.6;
      border-style: dashed;
      cursor: not-allowed;
    }
  }
  .goods-sku {
    padding-left: 10px;
    padding-top: 20px;
    dl {
      display: flex;
      padding-bottom: 20px;
      align-items: center;
      dt {
        width: 50px;
        color: #999;
      }
      dd {
        flex: 1;
        color: #666;
        > img {
          width: 50px;
          height: 50px;
          .sku-state-mixin ();
        }
        > span {
          display: inline-block;
          height: 30px;
          line-height: 28px;
          padding: 0 20px;
          .sku-state-mixin ();
        }
      }
    }
  }
  </style>
